/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.rs.service.impl;

import com.xy.biz.base.client.DictClient;
import com.xy.biz.rs.client.TechniqueClient;
import com.xy.biz.rs.domain.bo.ManufactureApplyBO;
import com.xy.biz.rs.domain.constants.ManufactureApplyConstants;
import com.xy.biz.rs.domain.query.ManufactureApplyQuery;
import com.xy.biz.rs.domain.req.GetNextSequenceRequest;
import com.xy.biz.rs.manager.ManufactureApplyManager;
import com.xy.biz.rs.service.ManufactureApplyService;
import com.xy.biz.uc.client.UserClient;
import com.xy.lang.domain.Result;
import com.xy.tool.concurrent.locks.DisLock;
import com.xy.tool.concurrent.locks.DisLockFactory;
import com.xy.tool.context.UserContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 *
 * @author wwj
 * @date 2021-4-14
 */
@Service
public class ManufactureApplyServiceImpl implements ManufactureApplyService {

	@Autowired
	private ManufactureApplyManager manufactureApplyManager;

	@Autowired
	private DisLockFactory disLockFactory;
	@Autowired
    private DictClient dictClient;
	@Autowired
    private TechniqueClient techniqueClient;
	@Autowired
    private UserClient userClient;


	@Override
	public Result<?> saveManufactureApply(ManufactureApplyBO manufactureApplyBO) {
		//查询是否有相同批号
		int count = manufactureApplyManager.countManufactureApply(ManufactureApplyQuery.builder()
				.batchCode(manufactureApplyBO.getBatchCode()).build());
		if (count > 0) {
			return Result.ofBadRequest("已存在相同批号");
		}
		String sequenceResource = getSequenceResource(manufactureApplyBO);
        DisLock disLock = disLockFactory.create();
		if (disLock.lock(sequenceResource, 5000L)) {
			try {
				int nextSequence = manufactureApplyManager.getNextSequence(
						GetNextSequenceRequest.builder()
								.productDictCode(manufactureApplyBO.getProductDictCode())
								.subProductDictCode(manufactureApplyBO.getSubProductDictCode())
								.batchCode(manufactureApplyBO.getBatchCode()).build());
				if (manufactureApplyBO.getSequence() == nextSequence) {
					buildBO(manufactureApplyBO);
					int affectedRows = manufactureApplyManager.saveManufactureApply(manufactureApplyBO);
					if (affectedRows > 0) {
						return Result.success();
					}
				}else {
					return Result.fail(null,"次序编号发生更改,系统已自动更新！",nextSequence);
				}
			}finally {
				disLock.unlock(sequenceResource);
			}
		}
		return Result.fail();
	}

    private String getSequenceResource(ManufactureApplyBO manufactureApplyBO) {
        return "sequence-"
                    + manufactureApplyBO.getProductDictCode()
                    + "-"
                    + manufactureApplyBO.getSubProductDictCode()
                    + "-"
                    + manufactureApplyBO.getBatchCode()
                    + "-"
                    + UserContextHolder.getUserId();
    }

    private void buildBO(ManufactureApplyBO manufactureApplyBO) {
		manufactureApplyBO.setCreateTime(LocalDateTime.now());
		manufactureApplyBO.setCreateUserId(UserContextHolder.getUserId());
		manufactureApplyBO.setDeleteFlag(false);
		manufactureApplyBO.setStatus(0);
		manufactureApplyBO.setTenantId(UserContextHolder.getTenantId());
		manufactureApplyBO.setUpdateTime(LocalDateTime.now());
	}

	@Override
	public Result<?> saveAllManufactureApply(Collection<ManufactureApplyBO> collection) {
		int affectedRows = manufactureApplyManager.saveAllManufactureApply(collection);
		if (affectedRows > 0) {
			return Result.success();
		}
		return Result.ofErrorRowsAffected();
	}

	@Override
	public Result<?> updateManufactureApply(ManufactureApplyBO manufactureApplyBO) {
        String sequenceResource = getSequenceResource(manufactureApplyBO);
        DisLock disLock = disLockFactory.create();
        if (disLock.lock(sequenceResource, 5000L)) {
            try {
                int nextSequence = manufactureApplyManager.getNextSequence(
                        GetNextSequenceRequest.builder()
                                .productDictCode(manufactureApplyBO.getProductDictCode())
                                .subProductDictCode(manufactureApplyBO.getSubProductDictCode())
                                .batchCode(manufactureApplyBO.getBatchCode()).build());
                if (manufactureApplyBO.getSequence() == nextSequence) {
                    buildBOForUpdate(manufactureApplyBO);
                    int affectedRows = manufactureApplyManager.updateManufactureApply(manufactureApplyBO);
                    if (affectedRows > 0) {
                        return Result.success();
                    }
                }else {
                    return Result.fail(null,"次序编号发生更改,系统已自动更新！",nextSequence);
                }
            }finally {
                disLock.unlock(sequenceResource);
            }
        }
        return Result.fail();
	}

    private void buildBOForUpdate(ManufactureApplyBO manufactureApplyBO) {
        manufactureApplyBO.setUpdateTime(LocalDateTime.now());
    }

    @Override
	public Result<?> deleteManufactureApply(Long manufactureApplyId) {
		int affectedRows = manufactureApplyManager.deleteManufactureApply(manufactureApplyId);
		if (affectedRows > 0) {
			return Result.success();
		}
		return Result.ofErrorRowsAffected();
	}

	@Override
	public ManufactureApplyBO getManufactureApply(Long manufactureApplyId) {
		return manufactureApplyManager.getManufactureApply(manufactureApplyId);
	}

	@Override
	public List<ManufactureApplyBO> listManufactureApplyById(Collection<Long> collection) {
		return manufactureApplyManager.listManufactureApplyById(collection);
	}

	@Override
	public List<ManufactureApplyBO> listManufactureApply(ManufactureApplyQuery query) {
        List<ManufactureApplyBO> manufactureApplyBOS = manufactureApplyManager.listManufactureApply(query);
        dictClient.buildByDict(manufactureApplyBOS,"product",bo->bo.getProductDictCode(),(bo,value)->bo.setProductDictValue(value));
        dictClient.buildByDict(manufactureApplyBOS,"product",bo->bo.getSubProductDictCode(),(bo,value)->bo.setSubProductDictValue(value));
        List<Long> techIds = manufactureApplyBOS.stream().map(ManufactureApplyBO::getTechniqueId).collect(Collectors.toList());
        techniqueClient.buildByTechnique(manufactureApplyBOS,techIds,ManufactureApplyBO::getTechniqueId,(ma,t)->ma.setTechDocumentName(t.getDocumentName()));
        List<Long> receiveUserIds = manufactureApplyBOS.stream().map(ManufactureApplyBO::getReceiveUserId).collect(Collectors.toList());
        userClient.buildByUser(manufactureApplyBOS,receiveUserIds,ManufactureApplyBO::getReceiveUserId,(ma,u)->ma.setReceiveUserName(u.getUserName()));
		List<Long> createUserIds = manufactureApplyBOS.stream().map(ManufactureApplyBO::getCreateUserId).collect(Collectors.toList());
		userClient.buildByUser(manufactureApplyBOS,createUserIds,ManufactureApplyBO::getCreateUserId,(ma,u)->ma.setCreateUserName(u.getUserName()));
		return manufactureApplyBOS;
	}

	@Override
	public int countManufactureApply(ManufactureApplyQuery query) {
		return manufactureApplyManager.countManufactureApply(query);
	}

	@Override
	public int getNextSequence(GetNextSequenceRequest request) {
		int sequenceNum = manufactureApplyManager.getNextSequence(request);
		return sequenceNum;
	}

    @Override
    public Result<?> updateManufactureApplyStatus(ManufactureApplyBO manufactureApplyBO) {
		if (ManufactureApplyConstants.STATUS_RELEASED == manufactureApplyBO.getStatus()) {
			manufactureApplyBO.setSendTime(LocalDateTime.now());
		}
        int row = manufactureApplyManager.updateManufactureApply(manufactureApplyBO);
        if (row > 0) {
            return Result.success();
        }
        return Result.fail();
    }

}
